/*
 * /linux-3.0.8/drivers/spi/gt210_nrf2401dev.c
 */
 
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/compat.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/spi/spi.h>

#include <mach/irqs.h>

#include <mach/regs-gpio.h>
#include <mach/gpio.h>

#include <asm/uaccess.h>
#include <plat/gpio-cfg.h>
#include <plat/s3c64xx-spi.h>

#include "gt210_nrf2401.h"


static struct spi_master *spi_mas0 = NULL;
static struct spi_device * spi_dev0 =  NULL;

static struct spi_master *spi_mas1 = NULL;
static struct spi_device * spi_dev1 =  NULL;



/***** spi board info and spi driver structure ****/
static int  gt210_nrf2401_init_pin(struct gt210_nrf2401_platdata *pdata)
{	//dprintk("gt210_nrf2401_init_pin()\n");
	int ret = 0;
	if (gpio_is_valid(pdata->ce_pin)){
		ret = gpio_request(pdata->ce_pin,"chip enable pin");
		if (ret < 0){
			printk(KERN_ERR "failed to request gpio: %d\n", pdata->ce_pin);
			return ret;
		}
		gpio_direction_output(pdata->ce_pin, 1);
		s3c_gpio_cfgpin(pdata->ce_pin, S3C_GPIO_SFN(1));
		s3c_gpio_setpull(pdata->ce_pin, S3C_GPIO_PULL_UP);
	}else{
		return -EINVAL;
	}
	if (gpio_is_valid(pdata->irq_pin)){
		ret = gpio_request(pdata->irq_pin,"chip irq pin");
		if (ret < 0){
			printk(KERN_ERR "failed to request gpio: %d\n", pdata->irq_pin);
			goto exit_1;
		}
		/* note: don't use S3C_GPIO_SFN(2) to set !!!*/
		s3c_gpio_cfgpin(pdata->irq_pin, S3C_GPIO_SFN(15));
		//s3c_gpio_cfgpin(pdata->irq_pin, S3C_GPIO_SFN(2));
		//s3c_gpio_setpull(pdata->irq_pin, S3C_GPIO_PULL_UP);
	}else{
		ret = -EINVAL;
		goto exit_1;
	}
	return ret;
	
exit_1:	
	gpio_free(pdata->ce_pin);
	return ret;
}
static void gt210_nrf2401_exit_pin(struct gt210_nrf2401_platdata *pdata)
{	//dprintk("gt210_nrf2401_exit_pin()\n");
	gpio_free(pdata->ce_pin);
	gpio_free(pdata->irq_pin);
};
static void gt210_nrf2401_set_cepin(struct gt210_nrf2401_platdata *pdata)
{
	gpio_set_value(pdata->ce_pin, 1);
};
static void gt210_nrf2401_clear_cepin(struct gt210_nrf2401_platdata *pdata)
{
	gpio_set_value(pdata->ce_pin, 0);
};


/* spi 0.0 device */
struct gt210_nrf2401_platdata gt210_nrf2401_pdata0 ={
	.en_aa = 1<<5|1<<4|1<<3|1<<2|1<<1|1<<0,		/* 0x01: auto ack */
	.en_rxaddr = 1<<5|1<<4|1<<3 | 1<<2|1<<1|1<<0,		/* 0x02: rx addr enable */
	.setup_aw = 1<<1 | 1<<0,		/* 0x03: addr width */
	.setup_retr = 0xf<<4 | 0xf<<0,		/* 0x04: retransmit */
	.rf_ch =0x2<<0,		/* 0x05: channel */
	.rf_setup = 0<<5 | 0<<4 | 1<<3 | 3<<1 | 1<<0,		/* 0x06: setup: rf baudrate */
	
	.rx_pw_p0 = 32,		/* 0x11: pipe width  */
	.rx_pw_p1 = 32,		/* 0x12: */
	.rx_pw_p2 = 32,		/* 0x13: */

	
	.rx_pw_p3 = 32,		/* 0x14: */
	.rx_pw_p4 = 32,		/* 0x15: */
	.rx_pw_p5 = 32,		/* 0x16: */
	
	.dynpld = 0<<5 |  0<<4 |  0<<3 |  0<<2 |  0<<1 |  0<<0,		/* 0x1c: dynamic payload */
	.feature = 0<<2 |  0<<1 |  0<<0 ,	/* 0x1d:  */


	.ce_pin  = S5PV210_GPH0(0),

	.irq = IRQ_EINT(1),
	.irq_pin = S5PV210_GPH0(1),
	.irq_flags = IRQF_TRIGGER_FALLING,

	.init_pin = gt210_nrf2401_init_pin,
	.exit_pin = gt210_nrf2401_exit_pin,
	
	.set_cepin = gt210_nrf2401_set_cepin,
	.clear_cepin = gt210_nrf2401_clear_cepin,

};
static struct s3c64xx_spi_csinfo gt210_nrf2401_spi0_csi[] = {
	[0] = {
		.line = S5PV210_GPB(1),
		.set_level = gpio_set_value,
		.fb_delay = 0x2,
	},
};
static struct spi_board_info gt210_nrf2401_board_info0 = {
	.modalias = SPI_DEVICE_NAME,	/* nrf2401_hub != spidev*/
	.irq = IRQ_EINT(1),
	.max_speed_hz = 5*1000*1000,
	.bus_num = 0,
	.chip_select = 0,
	.mode = SPI_MODE_0,
	.platform_data = &gt210_nrf2401_pdata0,
	.controller_data = &gt210_nrf2401_spi0_csi[0],
};



/* spi 1.0 device */
struct gt210_nrf2401_platdata gt210_nrf2401_pdata1 ={
	.en_aa = 1<<5|1<<4|1<<3|1<<2|1<<1|1<<0,		/* 0x01: auto ack */
	.en_rxaddr = 1<<5|1<<4|1<<3 | 1<<2|1<<1|1<<0,		/* 0x02: rx addr enable */
	.setup_aw = 1<<1 | 1<<0,		/* 0x03: addr width */
	.setup_retr = 0xf<<4 | 0xf<<0,		/* 0x04: retransmit */
	.rf_ch =0x2<<0,		/* 0x05: channel */
	.rf_setup = 0<<5 | 0<<4 | 1<<3 | 3<<1 | 1<<0,		/* 0x06: setup: rf baudrate */
	
	.rx_pw_p0 = 32,		/* 0x11: pipe width  */
	.rx_pw_p1 = 32,		/* 0x12: */
	.rx_pw_p2 = 32,		/* 0x13: */

	
	.rx_pw_p3 = 32,		/* 0x14: */
	.rx_pw_p4 = 32,		/* 0x15: */
	.rx_pw_p5 = 32,		/* 0x16: */
	
	.dynpld = 0<<5 |  0<<4 |  0<<3 |  0<<2 |  0<<1 |  0<<0,		/* 0x1c: dynamic payload */
	.feature = 0<<2 |  0<<1 |  0<<0 ,	/* 0x1d:  */

	.ce_pin  = S5PV210_GPH0(2),

	.irq = IRQ_EINT(3),
	.irq_pin = S5PV210_GPH0(3),
	.irq_flags = IRQF_TRIGGER_FALLING,

	.init_pin = gt210_nrf2401_init_pin,
	.exit_pin = gt210_nrf2401_exit_pin,
	
	.set_cepin = gt210_nrf2401_set_cepin,
	.clear_cepin = gt210_nrf2401_clear_cepin,

};
static struct s3c64xx_spi_csinfo gt210_nrf2401_spi1_csi[] = {
	[0] = {
		.line = S5PV210_GPB(5),
		.set_level = gpio_set_value,
		.fb_delay = 0x2,
	},
};
static struct spi_board_info gt210_nrf2401_board_info1 = {
	.modalias = SPI_DEVICE_NAME,	/* nrf2401 != spidev*/
	.irq = IRQ_EINT(3),
	.max_speed_hz = 5*1000*1000,
	.bus_num = 1,
	.chip_select = 0,
	.mode = SPI_MODE_0,
	.platform_data = &gt210_nrf2401_pdata1,
	.controller_data = &gt210_nrf2401_spi1_csi[0],
};



/***** init and exit ****/
static int __init gt210_nrf2401dev_init(void)
{	dprintk("gt210_nrf2401dev_init()\n");
	int ret;

	spi_mas0 = spi_busnum_to_master(gt210_nrf2401_board_info0.bus_num);
	if(spi_mas0 == NULL){
		printk(KERN_ERR"failed to find spi master \n");
		ret = PTR_ERR(spi_mas0);
		return ret;
	}
	spi_dev0 = spi_new_device(spi_mas0, &gt210_nrf2401_board_info0);
	if(spi_dev0 == NULL){
		printk(KERN_ERR"failed to create spi device \n");
		ret = PTR_ERR(spi_dev0);
		goto exit_1;
	}

	spi_mas1 = spi_busnum_to_master(gt210_nrf2401_board_info1.bus_num);
	if(spi_mas1 == NULL){
		printk(KERN_ERR"failed to find spi master \n");
		ret = PTR_ERR(spi_mas0);
		goto exit_2;
	}
	spi_dev1 = spi_new_device(spi_mas1, &gt210_nrf2401_board_info1);
	if(spi_dev1 == NULL){
		printk(KERN_ERR"failed to create spi device \n");
		ret = PTR_ERR(spi_dev1);
		goto exit_3;
	}	
	return 0;

exit_3:
	if(spi_dev1 != NULL) 
		put_device(&spi_mas1->dev);
	spi_mas1 = NULL;
exit_2:
	if(spi_dev0 != NULL) 
		spi_unregister_device(spi_dev0);
	spi_dev0 = NULL;
exit_1:
	if(spi_mas0 != NULL) 
		put_device(&spi_mas0->dev);
	spi_mas0 = NULL;
	return ret;
}
static void __exit gt210_nrf2401dev_exit(void)
{	dprintk("gt210_nrf2401dev_exit()\n");

	if(spi_dev0 != NULL) 
		spi_unregister_device(spi_dev0);
	if(spi_mas0 != NULL) 
		put_device(&spi_mas0->dev);

	if(spi_dev1 != NULL) 
		spi_unregister_device(spi_dev1);
	if(spi_mas1 != NULL) 
		put_device(&spi_mas1->dev);
}
module_init(gt210_nrf2401dev_init);
module_exit(gt210_nrf2401dev_exit);
MODULE_DESCRIPTION("GT2440 NRF2401 SPI Wireless Transceiver Device Driver");
MODULE_AUTHOR("Liguang13579<1659890447@qq.com>");
MODULE_LICENSE("GPL v2");
